﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System;

namespace Aj.Core
{

    /// <summary>
    /// Object扩展方法
    /// </summary>
    public static class ObjectExtensions
    {
        private static readonly object LockHelper = new object();

        #region ConvertTo
        public static object ConvertTo(this object value, Type targetType)
        {
            return value.ConvertTo(targetType, null);
        }
        public static object ConvertTo(this object value, Type targetType, object defaultValue)
        {
            if (value != null)
            {
                try
                {
                    var converter = TypeDescriptor.GetConverter(targetType);
                    if (converter != null && converter.CanConvertFrom(value.GetType()))
                    {
                        return converter.ConvertFrom(value);
                    }
                    converter = TypeDescriptor.GetConverter(value);
                    if (converter != null && converter.CanConvertTo(targetType))
                    {
                        return converter.ConvertTo(value, targetType);
                    }
                }
                catch
                {
                }
            }
            return defaultValue;
        }
        #endregion

        #region 安全的将对象转换为指定类型的数据
        /// <summary>
        /// 转换为8位无符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static byte ToTinyInt(this object objValue)
        {
            return objValue.ToTinyInt(0);
        }
        /// <summary>
        /// 转换为8位无符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static byte ToTinyInt(this object objValue, byte defValue)
        {
            byte val;
            if (objValue != null && byte.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为16位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static short ToSmallInt(this object objValue)
        {
            return objValue.ToSmallInt(0);
        }
        /// <summary>
        /// 转换为16位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static short ToSmallInt(this object objValue, short defValue)
        {
            Int16 val;
            if (objValue != null && Int16.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为32位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static int ToInt(this object objValue)
        {
            return objValue.ToInt(0);
        }
        /// <summary>
        /// 转换为32位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static int ToInt(this object objValue, int defValue)
        {
            Int32 val;
            if (objValue != null && Int32.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为64位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static long ToLong(this object objValue)
        {
            return objValue.ToLong(0);
        }
        /// <summary>
        /// 转换为64位有符号整数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static long ToLong(this object objValue, Int64 defValue)
        {
            Int64 val;
            if (objValue != null && Int64.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为单精度数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static float ToFloat(this object objValue)
        {
            return objValue.ToFloat(0);
        }
        /// <summary>
        /// 转换为单精度数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static float ToFloat(this object objValue, float defValue)
        {
            Single val;
            if (objValue != null && Single.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为十进制数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static decimal ToDecimal(this object objValue)
        {
            return objValue.ToDecimal(0);
        }
        /// <summary>
        /// 转换为十进制数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static decimal ToDecimal(this object objValue, decimal defValue)
        {
            Decimal val;
            if (objValue != null && Decimal.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为双精度数
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static double ToDouble(this object objValue)
        {
            return objValue.ToDouble(0);
        }
        /// <summary>
        /// 转换为双精度数
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static double ToDouble(this object objValue, Double defValue)
        {
            Double val;
            if (objValue != null && Double.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为布尔值
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static bool ToBool(this object objValue)
        {
            return objValue.ToBool(false);
        }
        /// <summary>
        /// 转换为布尔值
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static bool ToBool(this object objValue, bool defValue)
        {
            Boolean val;
            if (objValue != null && Boolean.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        /// <summary>
        /// 转换为日期值
        /// </summary>
        /// <param name="objValue"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this object objValue)
        {
            return objValue.ToDateTime(DateTime.Today);
        }
        /// <summary>
        /// 转换为日期值
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="defValue"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this object objValue, DateTime defValue)
        {
            DateTime val;
            if (objValue != null && DateTime.TryParse(objValue.ToString(), out val))
            {
                return val;
            }
            return defValue;
        }
        #endregion

        #region 执行对象方法
        /// <summary>
        /// 执行对象方法
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object InvokeMethod(this object obj, string methodName, params object[] parameters)
        {
            return InvokeMethod<object>(obj, methodName, parameters);
        }
        /// <summary>
        /// 执行对象方法
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="obj"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static TValue InvokeMethod<TValue>(this object obj, string methodName)
        {
            return InvokeMethod<TValue>(obj, methodName, null);
        }

        /// <summary>
        /// 执行对象方法
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="obj"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static TValue InvokeMethod<TValue>(this object obj, string methodName, params object[] parameters)
        {
            var type = obj.GetType();
            var method = type.GetMethod(methodName);

            if (method == null) throw new ArgumentException(string.Format("Method '{0}' not found.", methodName), methodName);

            var value = method.Invoke(obj, parameters);
            return (value is TValue ? (TValue)value : default(TValue));
        }
        #endregion

        #region 读取/设置属性值
        /// <summary>
        /// 读取属性值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetPropertyValue(this object obj, string propertyName)
        {
            return GetPropertyValue<object>(obj, propertyName, null);
        }
        /// <summary>
        /// 读取属性值
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static TValue GetPropertyValue<TValue>(this object obj, string propertyName)
        {
            return GetPropertyValue<TValue>(obj, propertyName, default(TValue));
        }
        /// <summary>
        /// 读取属性值
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static TValue GetPropertyValue<TValue>(this object obj, string propertyName, TValue defaultValue)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);

            if (property == null) throw new ArgumentException(string.Format("Property '{0}' not found.", propertyName), propertyName);

            var value = property.GetValue(obj, null);
            return (value is TValue ? (TValue)value : defaultValue);
        }
        ///<summary>
        /// 读取属性类型
        ///</summary>
        ///<param name="type"></param>
        ///<param name="propertyName"></param>
        ///<returns></returns>
        ///<exception cref="ArgumentException"></exception>
        public static Type GetPropertyType(this Type type, string propertyName)
        {
            var property = type.GetProperty(propertyName);
            if (property == null) throw new ArgumentException(string.Format("Property '{0}' not found.", propertyName), propertyName);
            Type propertyType = property.PropertyType;
            var underlyingType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
            return underlyingType;
        }
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        public static void SetPropertyValue(this object obj, string propertyName, object value)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);

            if (property == null) throw new ArgumentException(string.Format("Property '{0}' not found.", propertyName), propertyName);

            property.SetValue(obj, value, null);
        }
        #endregion

        #region 读取自定义属性
        /// <summary>
        /// 读取自定义属性
        /// </summary>
        /// <typeparam name="TAttr"></typeparam>
        /// <param name="obj"></param>
        /// <returns>返回第一个搜到</returns>
        public static TAttr GetAttribute<TAttr>(this ICustomAttributeProvider obj) where TAttr : Attribute
        {
            return GetAttribute<TAttr>(obj, true);
        }
        /// <summary>
        /// 读取自定义属性
        /// </summary>
        /// <typeparam name="TAttr"></typeparam>
        /// <param name="obj"></param>
        /// <param name="includeInherited"></param>
        /// <returns>返回第一个搜到</returns>
        public static TAttr GetAttribute<TAttr>(this ICustomAttributeProvider obj, bool includeInherited) where TAttr : Attribute
        {
            var attribute = obj.GetAttributes<TAttr>(includeInherited).FirstOrDefault();
            if (attribute.IsNotNull())
            {
                return attribute;
            }
            return null;
        }
        /// <summary>
        /// 读取自定义属性数组
        /// </summary>
        /// <typeparam name="TAttr"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static IEnumerable<TAttr> GetAttributes<TAttr>(this ICustomAttributeProvider obj) where TAttr : Attribute
        {
            return GetAttributes<TAttr>(obj, true);
        }
        /// <summary>
        /// 读取自定义属性数组
        /// </summary>
        /// <typeparam name="TAttr"></typeparam>
        /// <param name="obj"></param>
        /// <param name="includeInherited"></param>
        /// <returns></returns>
        public static IEnumerable<TAttr> GetAttributes<TAttr>(this ICustomAttributeProvider obj, bool includeInherited) where TAttr : Attribute
        {
            object[] attributes = obj.GetCustomAttributes(typeof(TAttr), includeInherited);
            //return attributes.OfType<TAttr>();
            foreach (var attribute in attributes)
            {
                if (attribute is TAttr)
                {
                    yield return (TAttr)attribute;
                }
            }
        }
        #endregion

        #region 判断类型
        /// <summary>
        /// 判断是否类实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool InstanceOf<T>(this object value)
        {
            return value.IsType(typeof(T));
        }
        /// <summary>
        /// 判断是否某种类型
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsType(this object obj, Type type)
        {
            return obj.GetType().Equals(type);
        }
        /// <summary>
        /// 判断是否数组
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool IsArray(this object obj)
        {
            return obj.IsType(typeof(Array));
        }
        /// <summary>
        /// 判断是否DBNULL
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool IsDbNull(this object obj)
        {
            return obj.IsType(typeof(DBNull));
        }
        /// <summary>
        /// 判断是否null
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static bool IsNull(this object @this)
        {
            return @this == null;
        }
        /// <summary>
        /// 判断是否非null
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static bool IsNotNull(this object @this)
        {
            return @this != null;
        }
        /// <summary>
        /// 判断是否null或者空
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string @this)
        {
            return string.IsNullOrEmpty(@this);
        }
        /// <summary>
        /// 判断是否不为null或者空
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static bool IsNotNullAndEmpty(this string @this)
        {
            return !string.IsNullOrEmpty(@this);
        }

        #endregion

        #region 序列化函数
        /// <summary>
        /// 序列化对象为字节数组
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte[] SerializeObject(this object value)
        {
            if (value.IsNull())
            {
                return null;
            }
            byte[] buffer = null;
            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, value);
                    stream.Position = 0L;
                    buffer = stream.ToArray();
                    stream.Close();
                }
            }
            catch
            {
            }

            return buffer;
        }
        /// <summary>
        /// 字节数组反序列化为对象
        /// </summary>
        /// <param name="pBytes"></param>
        /// <returns></returns>
        public static object DeserializeObject(this byte[] pBytes)
        {
            if (pBytes.IsNull())
            {
                return null;
            }
            object obj = null;
            try
            {
                using (MemoryStream stream = new MemoryStream(pBytes))
                {
                    IFormatter formatter = new BinaryFormatter();
                    stream.Position = 0L;
                    obj = formatter.Deserialize(stream);
                    stream.Close();
                }
            }
            catch
            {

            }
            return obj;
        }
        /// <summary>
        /// 序列化对象为xml文件
        /// </summary>
        /// <param name="value"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool SerializeXmlFile(this object value, string fileName)
        {
            bool success = false;

            FileStream fs = null;
            try
            {
                fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                XmlSerializer serializer = new XmlSerializer(value.GetType());
                serializer.Serialize(fs, value);
                success = true;
            }
            catch
            {
                success = false;
            }
            finally
            {
                if (fs != null) fs.Close();
            }
            return success;
        }
        /// <summary>
        /// XML文件反序列化为对象
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object DeserializeXmlFile(this string fileName, Type type)
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                XmlSerializer serializer = new XmlSerializer(type);
                return serializer.Deserialize(fs);
            }
            catch
            {
                return null;
            }
            finally
            {
                if (fs != null) fs.Close();
            }
        }
        /// <summary>
        /// 序列化对象为xml字符
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string SerializeXml(this object value)
        {
            if (value.IsNull())
            {
                return null;
            }
            try
            {
                var serializer = new XmlSerializer(value.GetType());
                var writer = new StringWriter();
                serializer.Serialize(writer, value);
                return writer.ToString();
            }
            catch
            {
            }

            return null;
        }
        /// <summary>
        /// xml字符反序列化为对象
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object DeserializeXml(this string xml, Type type)
        {
            if (xml.IsNullOrEmpty())
            {
                return null;
            }
            try
            {
                using (TextReader textReader = new StringReader(xml))
                {
                    XmlSerializer serializer = new XmlSerializer(type);
                    return serializer.Deserialize(textReader);
                }
            }
            catch
            {
            }
            return null;
        }
        #endregion

        ///<summary>
        /// 字符串分割数组
        ///</summary>
        ///<param name="self"></param>
        ///<param name="separator"></param>
        ///<returns></returns>
        public static IEnumerable<string> Split(this string self, char separator)
        {
            return self.Split(separator);
        }
        ///<summary>
        /// 字符串分割数组
        ///</summary>
        ///<param name="self"></param>
        ///<param name="separator"></param>
        ///<returns></returns>
        public static IEnumerable<string> Split(this string self, string separator)
        {
            return self.Split(separator.ToCharArray());
        }
        /// <summary>
        /// 判断是否Email地址
        /// </summary>
        /// <param name="self"></param>
        /// <returns></returns>
        public static bool IsValidEmailAddress(this string self)
        {
            Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
            return regex.IsMatch(self);
        }
        ///<summary>
        /// 日期增加1周
        ///</summary>
        ///<param name="dateTime"></param>
        ///<returns></returns>
        public static DateTime AddWeek(this DateTime dateTime)
        {
            return dateTime.AddDays(7.0);
        }
        /// <summary>
        /// UnixTimestamp
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static long ToUnixTimestamp(this DateTime date)
        {
            DateTime time = new DateTime(0x7b2, 1, 1, 0, 0, 0);
            TimeSpan span = date - time;
            return (long)span.TotalSeconds;
        }
        /// <summary>
        /// 获取RFC822文档定义的时间格式字符串,如: Thu, 21 Dec 2000 16:01:07 +0800
        /// </summary>
        /// <param name="time">需要转换的时间</param>
        /// <returns>RFC822格式表示的时间字符串</returns>
        public static string ToRFC822Time(this DateTime time)
        {
            string rfcTime = time.ToString("ddd, dd MMM yyyy HH':'mm':'ss", CultureInfo.InvariantCulture);
            rfcTime += time.ToString(" zzz").Replace(":", "");
            return rfcTime;
        }
        /// <summary>
        /// 从流中读取所有文本
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string ReadAllText(this Stream stream, Encoding encoding)
        {
            using (StreamReader reader = new StreamReader(stream, encoding))
            {
                return reader.ReadToEnd();
            }
        }
        /// <summary>
        /// 从流中读取所有文本
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static string ReadAllText(this Stream stream)
        {
            return stream.ReadAllText(Encoding.UTF8);
        }
        ///<summary>
        /// 从流中读取字节数组
        ///</summary>
        ///<param name="stream"></param>
        ///<returns></returns>
        public static byte[] ToByteArray(this Stream stream)
        {
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            return buffer;
        }

        public static void ExecEach<T>(this IEnumerable<T> sequence, Action<T> action)
        {
            if (sequence == null)
            {
                throw new ArgumentNullException("sequence");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            foreach (T local in sequence)
            {
                local.Exec(action);
            }
        }

        public static void Exec<T>(this T obj, Action<T> action)
        {
            action(obj);
        }

        public static IEnumerable<TResult> ExecEach<T, TResult>(this IEnumerable<T> sequence, Func<T, TResult> action)
        {
            if (sequence == null)
            {
                throw new ArgumentNullException("sequence");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            return sequence.Select(local => local.Exec(action));
        }

        public static TResult Exec<T, TResult>(this T obj, Func<T, TResult> action)
        {
            return action(obj);
        }

        public static void AsycExec<T>(this T obj, Action<T> action)
        {
            action.BeginInvoke(obj, null, null);
        }

        public static void LockExec<T>(this T obj, Action<T> action) where T : class
        {
            lock (obj)
            {
                action(obj);
            }
        }

        public static void ExecAndLogExcetion<T>(this T obj, Action<T> action)
        {
            try
            {
                action(obj);
            }
            catch (Exception ex)
            {
                Function.WriteErrorLog(ex);
                throw;
            }
        }

        public static void ExecAndLogExcetion<T1, T2>(this T1 obj, T2 obj1, Action<T1, T2> action)
        {
            try
            {
                action(obj, obj1);
            }
            catch (Exception ex)
            {
                Function.WriteErrorLog(ex);
                throw;
            }
        }

        public static TResult ExecAndLogExcetion<T, TResult>(this T obj, Func<T, TResult> func)
        {
            try
            {
                return func(obj);
            }
            catch (Exception ex)
            {
                Function.WriteErrorLog(ex);
                throw;
            }
        }

        public static TResult ExecAndLogExcetion<T1, T2, TResult>(this T1 obj, T2 obj1, Func<T1, T2, TResult> func)
        {
            try
            {
                return func(obj, obj1);
            }
            catch (Exception ex)
            {
                Function.WriteErrorLog(ex);
                throw;
            }
        }
    }
}
